package com.example.shirodemo.authentication;

import com.example.core.libs.AppException;
import com.example.core.utils.JwtUtils;
import com.example.core.utils.RedisUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

@Component
public class JwtFilter extends BasicHttpAuthenticationFilter {
    @Autowired
    JwtUtils jwtUtils;
    @Autowired
    RedisUtil redisUtil;

    /**
     * 执行登录
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        //获取用户凭证
        String token = getAuthzHeader(request);

        try {
            // 走到JwtShiroRealm
            JwtToken jwtToken = new JwtToken(token);
            getSubject(request, response).login(jwtToken);
        } catch (UnknownAccountException | IncorrectCredentialsException | LockedAccountException e) {
            throw new AppException(e.getMessage());
        } catch (AuthenticationException e) {
            throw new AppException("认证失败！");
        }

        return true;
    }

    /**
     * 是否放行
     *
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @SneakyThrows
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (isLoginAttempt(request, response)) {
            super.executeLogin(request, response);
        } else {
            throw new AppException(HttpStatus.UNAUTHORIZED.value(), "凭证不能为空");
        }
        return true;
    }

    /**
     * 检查头部是否有token
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        return StringUtils.isNoneBlank(getTokenFromRequest(request));
    }

    // 从请求中获取 token
    private String getTokenFromRequest(ServletRequest request) {
        return getAuthzHeader(request);
    }
}
